package com.rui.decorator.main;

import com.rui.decorator.model.*;
import com.rui.decorator.obj.FriedRice;
import com.rui.decorator.obj.FriedRiceAddEgg;
import com.rui.decorator.obj.FriedRiceAddEggAndHam;

/**
 * 装饰模式（Decorator Pattern）
 * <p>
 * 装饰模式，是指在不改变原有对象的基础上，将功能附加到对象上，提供了比继承更有弹性的替代方案（扩展原有对象的功能）
 * <p>
 * 装饰（Decorator）模式中的角色：
 * 抽象构件（Component）角色 ：定义一个抽象接口以规范准备接收附加责任的对象。
 * 具体构件（Concrete Component）角色 ：实现抽象构件，通过装饰角色为其添加一些职责。
 * 抽象装饰（Decorator）角色 ： 继承或实现抽象构件，并包含具体构件的实例，可以通过其子类扩展具体构件的功能。
 * 具体装饰（ConcreteDecorator）角色 ：实现抽象装饰的相关方法，并给具体构件对象添加附加的责任。
 * <p>
 * <p>
 * 装饰器模式与代理模式对比：
 * 装饰器模式就是一种特殊的代理模式。
 * 装饰器模式强调自身的功能扩展，用自己说了算的透明扩展，可动态定制的扩展；代理模式强调代理过程的控制。
 * 获取目标对象构建的地方不同，装饰者是从外界传递进来的，可以通过构造方法传递；静态代理是在代理类内部创建，以此来隐藏目标对象。
 * <p>
 * 适用场景：
 * 用于扩展一个类的功能或者给一个类添加附加职责。
 * 动态的给一个对象添加功能，这些功能同样也可以再动态的撤销。
 * <p>
 * 优点：
 * 装饰器是继承的有力补充，比继承灵活，不改变原有对象的情况下动态地给一个对象扩展功能，即插即用。
 * 通过使用不同装饰类以及这些装饰类的排列组合，可实现不同效果。
 * 装饰器完全遵守开闭原则。
 * <p>
 * 缺点：
 * 会出现更多的代码，更多的类，增加程序的复杂性。
 * 动态装饰时，多层装饰会更复杂。
 *
 * @author ZhangRui
 * @date 2023/03/03 09:30
 **/
public class DecoratorMain {


    public static void main(String[] args) {

        // 普通继承模式-重写方法
        testExtend();

        // 装饰模式
        testDecorator();
    }

    /**
     * 装饰模式
     *
     * @param null
     * @return
     * @author ZhangRui
     * @date 2023/3/3 9:39
     */
    private static void testDecorator() {
        FriedRice friedRice = new FriedRice();
        // 炒饭5元
        System.out.println(friedRice.getDesc() + friedRice.getPrice() + "元");

        friedRice = new Egg(friedRice);
        // 炒饭+鸡蛋7元
        System.out.println(friedRice.getDesc() + friedRice.getPrice() + "元");

        friedRice = new Egg(friedRice);
        // 炒饭+鸡蛋+鸡蛋9元
        System.out.println(friedRice.getDesc() + friedRice.getPrice() + "元");

        friedRice = new Ham(friedRice);
        // 炒饭+鸡蛋+鸡蛋+火腿12元
        System.out.println(friedRice.getDesc() + friedRice.getPrice() + "元");
    }

    /**
     * 继承方式
     *
     * @param null
     * @return
     * @author ZhangRui
     * @date 2023/3/3 9:35
     */
    private static void testExtend() {

        FriedRice friedRice = new FriedRice();
        // 炒饭5元
        System.out.println(friedRice.getDesc() + friedRice.getPrice() + "元");

        FriedRice friedRiceAddEgg = new FriedRiceAddEgg();
        // 炒饭+鸡蛋7元
        System.out.println(friedRiceAddEgg.getDesc() + friedRiceAddEgg.getPrice() + "元");

        FriedRice friedRiceAddEggAndHam = new FriedRiceAddEggAndHam();
        // 炒饭+鸡蛋+火腿10元
        System.out.println(friedRiceAddEggAndHam.getDesc() + friedRiceAddEggAndHam.getPrice() + "元");
    }
}
